什么是Describer
Describer是Kubectl上用来描述对象具体信息的,和kubectl describe
配合使用。
在/pkg/kubectl/cmd/util/factory.go中,有Describer()函数,可以依据mapping生成合适的Describer。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| func (f *factory) Describer(mapping *meta.RESTMapping) (kubectl.Describer, error) { mappingVersion := mapping.GroupVersionKind.GroupVersion() if mapping.GroupVersionKind.Group == federation.GroupName { fedClientSet, err := f.clients.FederationClientSetForVersion(&mappingVersion) if err != nil { return nil, err } if mapping.GroupVersionKind.Kind == "Cluster" { return &kubectl.ClusterDescriber{Interface: fedClientSet}, nil } } clientset, err := f.clients.ClientSetForVersion(&mappingVersion) if err != nil { return nil, err } if describer, ok := kubectl.DescriberFor(mapping.GroupVersionKind.GroupKind(), clientset); ok { return describer, nil } return nil, fmt.Errorf("no description has been implemented for %q", mapping.GroupVersionKind.Kind) }
|
Describer
Describer定义在/pkg/kubectl/describe.go中:
1 2 3 4 5 6
| type Describer interface { Describe(namespace, name string, describerSettings DescriberSettings) (output string, err error) }
|
可以看到,只要实现了Describe()的结构体都可以称为Describer。
所以,在/pkg/kubectl/describer.go中,实现了PodDescriber, ReplicationControllerDescriber, SecretDescriber, ServiceDescriber, ServiceAccountDescriber, NodeDescriber, LimitRangeDescriber, ResourceQuotaDescriber, PersistentVolumeDescriber, PersistentVolumeClaimDescriber, NamespaceDescriber, EndpointsDescriber, ConfigMapDescriber, ReplicaSetDescriber, HorizontalPodAutoscalerDescriber, NetworkPolicyDescriber, HorizontalPodAutoscalerDescriber, DaemonSetDescriber, DeploymentDescriber, JobDescriber, IngressDescriber, JobDescriber, CronJobDescriber, StatefulSetDescriber, CertificateSigningRequestDescriber, StorageClassDescriber, PodDisruptionBudgetDescriber。
在实现Describer的结构体中,通常会嵌入一个clientset,用来在Describe()中获取具体的Object。比如说下面的ReplicationControllerDescriber。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| type ReplicationControllerDescriber struct { clientset.Interface } func (d *ReplicationControllerDescriber) Describe(namespace, name string, describerSettings DescriberSettings) (string, error) { rc := d.Core().ReplicationControllers(namespace) pc := d.Core().Pods(namespace) controller, err := rc.Get(name) if err != nil { return "", err } running, waiting, succeeded, failed, err := getPodStatusForController(pc, labels.SelectorFromSet(controller.Spec.Selector)) if err != nil { return "", err } var events *api.EventList if describerSettings.ShowEvents { events, _ = d.Core().Events(namespace).Search(controller) } return describeReplicationController(controller, events, running, waiting, succeeded, failed) }
|
DescriberMap
DescriberMap中记录了GK和Describer的关系。这里使用GK作为Key,因为GK足以标记一个类型。目前还不支持同名Kind出现在不同的Group(internal除外)中(否则resource无法找到合适的GVK),所以感觉完全可以仅使用Kind作为Key。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| func describerMap(c clientset.Interface) map[unversioned.GroupKind]Describer { m := map[unversioned.GroupKind]Describer{ api.Kind("Pod"): &PodDescriber{c}, api.Kind("ReplicationController"): &ReplicationControllerDescriber{c}, api.Kind("Secret"): &SecretDescriber{c}, api.Kind("Service"): &ServiceDescriber{c}, api.Kind("ServiceAccount"): &ServiceAccountDescriber{c}, api.Kind("Node"): &NodeDescriber{c}, api.Kind("LimitRange"): &LimitRangeDescriber{c}, api.Kind("ResourceQuota"): &ResourceQuotaDescriber{c}, api.Kind("PersistentVolume"): &PersistentVolumeDescriber{c}, api.Kind("PersistentVolumeClaim"): &PersistentVolumeClaimDescriber{c}, api.Kind("Namespace"): &NamespaceDescriber{c}, api.Kind("Endpoints"): &EndpointsDescriber{c}, api.Kind("ConfigMap"): &ConfigMapDescriber{c}, extensions.Kind("ReplicaSet"): &ReplicaSetDescriber{c}, extensions.Kind("HorizontalPodAutoscaler"): &HorizontalPodAutoscalerDescriber{c}, extensions.Kind("NetworkPolicy"): &NetworkPolicyDescriber{c}, autoscaling.Kind("HorizontalPodAutoscaler"): &HorizontalPodAutoscalerDescriber{c}, extensions.Kind("DaemonSet"): &DaemonSetDescriber{c}, extensions.Kind("Deployment"): &DeploymentDescriber{c}, extensions.Kind("Job"): &JobDescriber{c}, extensions.Kind("Ingress"): &IngressDescriber{c}, batch.Kind("Job"): &JobDescriber{c}, batch.Kind("CronJob"): &CronJobDescriber{c}, apps.Kind("StatefulSet"): &StatefulSetDescriber{c}, certificates.Kind("CertificateSigningRequest"): &CertificateSigningRequestDescriber{c}, storage.Kind("StorageClass"): &StorageClassDescriber{c}, policy.Kind("PodDisruptionBudget"): &PodDisruptionBudgetDescriber{c}, } return m }
|
Describer的入口
最后来看下Describer的入口。
之前我们看到,可以使用下面的代码获取Describer
1 2 3 4
| if describer, ok := kubectl.DescriberFor(mapping.GroupVersionKind.GroupKind(), clientset); ok { return describer, nil }
|
所以来看来/pkg/kubectl/describe.go中的DescriberFor()函数:
1 2 3 4 5
| func DescriberFor(kind unversioned.GroupKind, c clientset.Interface) (Describer, bool) { f, ok := describerMap(c)[kind] return f, ok }
|
函数的实现很简单,先调用describerMap()生成DescriberMap,然后找到对应kind的Describer。